package com.sl.water.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sl.common.ResponseData;
import com.sl.model.enums.RehearsalSchemeTypeEnum;
import com.sl.common.exception.SchemeNotFoundException;
import com.sl.common.exception.model.ModelCalculationException;
import com.sl.water.api.RehearsalPythonService;
import com.sl.water.dao.RehearsalSchemeDao;
import com.sl.water.entity.*;
import com.sl.water.service.*;
import com.sl.water.vo.FastRehearsalFlowVO;
import com.sl.water.vo.FastRehearsalRainfallVO;
import com.sl.water.vo.FastRehearsalVO;
import com.sl.water.vo.RehearsalParamsVO;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


@Service
public class RehearsalSchemeServiceImpl extends ServiceImpl<RehearsalSchemeDao, RehearsalScheme> implements RehearsalSchemeService {

    /**
     * 模型参数
     */
    @Value("${python-model.model-param:}")
    private String modelParam;

    @Resource
    private BRCunService brCunService;

    @Resource
    private BRDmService brDmService;

    @Resource
    private BRYldService brYldService;

    @Resource
    private BRCompanyService brCompanyService;

    @Resource
    private BRInfoService brInfoService;

    @Resource
    private RehearsalPythonService rehearsalPythonService;

    @Resource
    private ForecastSchemeService forecastSchemeService;

    @Resource
    JdbcTemplate jdbcTemplate;


    private JSONObject getModelParamsAndSimulationDuration(RehearsalScheme rehearsalScheme, String kind) {
        JSONObject modelParamsAndSimulationDuration = new JSONObject();
        int type = rehearsalScheme.getType();
        JSONArray modelParams = new JSONArray();
        int simulationDuration;
        if (Objects.equals(rehearsalScheme.getType(), RehearsalSchemeTypeEnum.TYPICAL.getValue()))
            throw new RuntimeException("典型场景不允许执行");
        if (ObjectUtils.isEmpty(rehearsalScheme.getParamsJson()))
            throw new RuntimeException("参数不能为空");
        if (Objects.equals(rehearsalScheme.getType(), RehearsalSchemeTypeEnum.FAST.getValue())) {
            //不需要重新计算
            simulationDuration = rehearsalScheme.getSimulationDuration();
            if (kind.equalsIgnoreCase("bfh")) {
                if (StringUtils.isEmpty(rehearsalScheme.getParamsBfh()))
                    throw new RuntimeException("不分洪参数为空，不允许执行");
                modelParams = JSONUtil.parseArray(rehearsalScheme.getParamsBfh());
            } else {
                if (StringUtils.isEmpty(rehearsalScheme.getParamsFh()))
                    throw new RuntimeException("分洪参数为空，不允许执行");
                modelParams = JSONUtil.parseArray(rehearsalScheme.getParamsFh());
            }
        } else {
            JSONObject jsonObject = JSONUtil.parseObj(rehearsalScheme.getParamsJson());
            if (type == 0) {
                //人工预演
                int time = Optional.ofNullable(jsonObject.getInt("time")).orElse(0);
                simulationDuration = modelTime(time);
            } else {
                if (rehearsalScheme.getSimulationDuration() == null) {
                    throw new RuntimeException("模拟时长不能为空");
                }
                simulationDuration = rehearsalScheme.getSimulationDuration();
            }
            JSONArray rainfallProcess = jsonObject.getJSONArray("rainfallProcess");
            addZero(rainfallProcess, simulationDuration);
            JSONArray inq = jsonObject.getJSONArray("inq");
            addZero(inq, simulationDuration);
            JSONArray fhq = new JSONArray();
            if ("fh".equals(kind)) {
                for (int i = 0; i < simulationDuration; i++) {
                    fhq.add(rehearsalScheme.getFhFlow());
                }
            }
            addZero(fhq, simulationDuration);
            modelParams.addAll(rainfallProcess);
            modelParams.addAll(inq);
            modelParams.addAll(fhq);
        }
        modelParamsAndSimulationDuration.set("modelParams", modelParams).set("simulationDuration", simulationDuration);
        return modelParamsAndSimulationDuration;
    }

    @Override
    public Page<RehearsalScheme> pageList(int page, int size, Integer type, Integer status1, Integer status2) {
        LambdaQueryWrapper<RehearsalScheme> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(type), RehearsalScheme::getType, type)
                .eq(ObjectUtils.isNotEmpty(status1), RehearsalScheme::getStatus1, status1)
                .eq(ObjectUtils.isNotEmpty(status2), RehearsalScheme::getStatus2, status2)
                .orderByDesc(RehearsalScheme::getCreatedTime);
        return this.page(new Page<>(page, size), queryWrapper);
    }

    @Override
    @Transactional
    public void removeScheme(long id) {
        this.removeById(id);
        this.removeByIdAndKind(id, null);
    }

    @Override
    public RehearsalParamsVO getRehearsalParamsById(long id) {
        RehearsalScheme scheme = getScheme(id);
        Integer type = scheme.getType();
        String paramsJson = scheme.getParamsJson();
        if (Objects.equals(type, RehearsalSchemeTypeEnum.TYPICAL.getValue())) {
            throw new RuntimeException("典型预演没有参数");
        }
        if (StringUtils.isEmpty(paramsJson)) {
            throw new RuntimeException("参数值为空");
        }
        JSONObject paramsObj = JSONUtil.parseObj(paramsJson);
        if (Objects.equals(type, RehearsalSchemeTypeEnum.FAST.getValue())) {
            //快速预演
            Integer inqTime = paramsObj.getJSONObject("flow").getInt("time");
            Integer rainfallTime = paramsObj.getJSONObject("rainfall").getInt("time");
            String params = StringUtils.isNotEmpty(scheme.getParamsFh()) ? scheme.getParamsFh() : scheme.getParamsBfh();

            if (StringUtils.isEmpty(params)) {
                throw new RuntimeException("参数值为空");
            }
            List<Double> paramsList = JSONUtil.toList(params, Double.class);
            Integer simulationDuration = scheme.getSimulationDuration();
            //时间间隔参数
            int timeInterval = getTimeInterval(simulationDuration);
            //时间间隔所需的模拟数量
            int num = simulationDuration / timeInterval;
            List<Double> rainfall = paramsList.subList(0, num);
            List<Double> inq = paramsList.subList(num, num + num);
            return RehearsalParamsVO.builder()
                    .inqTime(inqTime).inq(inq.subList(0, inqTime))
                    .rainfall(rainfall.subList(0, rainfallTime)).rainfallTime(rainfallTime).build();

        } else {
            List<Double> inq = paramsObj.getBeanList("inq", Double.class);
            List<Double> rainfallProcess = paramsObj.getBeanList("rainfallProcess", Double.class);
            Integer time = 0;
            if (Objects.equals(type, RehearsalSchemeTypeEnum.ARTIFICIAL.getValue())) {
                //人工预演
                time = paramsObj.getInt("time");
            } else if (Objects.equals(type, RehearsalSchemeTypeEnum.AUTO.getValue())) {
                //自动预演
                time = scheme.getSimulationDuration();
            }
            return RehearsalParamsVO.builder()
                    .inqTime(time).inq(inq)
                    .rainfall(rainfallProcess).rainfallTime(time).build();
        }
    }


    @Override
    public List<RehearsalScheme> listByType(Integer type, Integer status1, Integer status2) {
        LambdaQueryWrapper<RehearsalScheme> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(ObjectUtils.isNotEmpty(type), RehearsalScheme::getType, type)
                .eq(ObjectUtils.isNotEmpty(status1), RehearsalScheme::getStatus1, status1)
                .eq(ObjectUtils.isNotEmpty(status2), RehearsalScheme::getStatus2, status2)
                .orderByDesc(RehearsalScheme::getCreatedTime);
        return this.list(queryWrapper);
    }

    @Override
    @Transactional
    public boolean updateStatus(Long id, Integer status, String error, String kind) {
        RehearsalScheme rehearsalScheme = new RehearsalScheme();
        if ("bfh".equals(kind)) {
            rehearsalScheme.setStatus1(status);
        } else {
            rehearsalScheme.setStatus2(status);
        }
        rehearsalScheme.setError(Objects.nonNull(error) ? error : "");
        UpdateWrapper<RehearsalScheme> updateWrapper = Wrappers.update();
        updateWrapper.eq("id", id);
        return this.update(rehearsalScheme, updateWrapper);
    }

    @Override
    public RehearsalScheme getByIdAndStatus(Long id, Integer status1, Integer status2) {
        LambdaQueryWrapper<RehearsalScheme> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RehearsalScheme::getId, id);
        if (ObjectUtils.isNotEmpty(status1)) {
            queryWrapper.eq(RehearsalScheme::getStatus1, status1);
        }
        if (ObjectUtils.isNotEmpty(status2)) {
            queryWrapper.eq(RehearsalScheme::getStatus2, status2);
        }
        return this.getOne(queryWrapper);
    }


    private void updateParams(RehearsalScheme scheme, String kind) {
        JSONObject modelParamsAndSimulationDuration = getModelParamsAndSimulationDuration(scheme, kind);
        String modelParams = modelParamsAndSimulationDuration.getStr("modelParams");
        int time = modelParamsAndSimulationDuration.getInt("simulationDuration");
        LambdaUpdateWrapper<RehearsalScheme> updateWrapper = Wrappers.lambdaUpdate();
        if ("bfh".equals(kind)) {
            scheme.setStatus1(1);
            scheme.setParamsBfh(modelParams);
        } else {
            scheme.setStatus2(1);
            scheme.setParamsFh(modelParams);
        }
        scheme.setError("");
        scheme.setSimulationDuration(time);
        scheme.setUpdatedTime(LocalDateTime.now());
        updateWrapper.set(RehearsalScheme::getStatus1, scheme.getStatus1()).set(RehearsalScheme::getParamsBfh, scheme.getParamsBfh())
                .set(RehearsalScheme::getStatus2, scheme.getStatus2()).set(RehearsalScheme::getParamsFh, scheme.getParamsFh())
                .set(RehearsalScheme::getError, scheme.getError()).set(RehearsalScheme::getSimulationDuration, scheme.getSimulationDuration())
                .set(RehearsalScheme::getUpdatedTime, scheme.getUpdatedTime())
                .eq(RehearsalScheme::getId, scheme.getId());
        this.update(updateWrapper);
    }

    @Override
    @Transactional
    public void runModelCall(RehearsalScheme rehearsalScheme, String kind, boolean bModifyState) {
        //删除村、易涝点、断面数据
        removeByIdAndKind(rehearsalScheme.getId(), kind);
        //更新状态为计算中，更新模型参数，更新模拟时长
        updateParams(rehearsalScheme, kind);
        try {
            rehearsalPythonService.callPythonApi(rehearsalScheme, kind);
        } catch (Exception e) {
            if (!bModifyState) {
                throw e;
            }
            updateStatus(rehearsalScheme.getId(), 3, e.toString(), kind);
        }
    }

    @Override
    public RehearsalScheme getScheme(long id) {
        RehearsalScheme rehearsalScheme = this.getById(id);
        if (rehearsalScheme == null) {
            throw new SchemeNotFoundException("方案不存在");
        }
        return rehearsalScheme;
    }

    private void removeByIdAndKind(long id, String kind) {
        //删除村
        brCunService.remove(Wrappers.lambdaQuery(BRCun.class).eq(BRCun::getSId, id).eq(StringUtils.isNotEmpty(kind), BRCun::getKind, kind));
        //删除断面
        brDmService.remove(Wrappers.lambdaQuery(BRDm.class).eq(BRDm::getSId, id).eq(StringUtils.isNotEmpty(kind), BRDm::getKind, kind));
        //删除易涝点
        brYldService.remove(Wrappers.lambdaQuery(BRYld.class).eq(BRYld::getSId, id).eq(StringUtils.isNotEmpty(kind), BRYld::getKind, kind));
        //删除企业厂区结果
        brCompanyService.remove(Wrappers.lambdaQuery(BRCompany.class).eq(BRCompany::getSId, id).eq(StringUtils.isNotEmpty(kind), BRCompany::getKind, kind));
        //删除汇总结果
        brInfoService.remove(Wrappers.lambdaQuery(BRInfo.class).eq(BRInfo::getSId, id).eq(StringUtils.isNotEmpty(kind), BRInfo::getKind, kind));
    }

    @Override
    public JSONObject cunList(long id, String kind) {
        RehearsalScheme rehearsalScheme = this.getById(id);
        if (rehearsalScheme == null) {
            throw new SchemeNotFoundException("方案不存在");
        }
        int simulationDuration = rehearsalScheme.getSimulationDuration();
        int timeInterval = getTimeInterval(simulationDuration);
        String sql = "SELECT t,xz_name,depthLevel,SUM(s.area) as totalArea FROM (" +
                "SELECT t,xz_name,area,CASE WHEN depth < 0.5 THEN 0 WHEN depth >= 0.5 AND depth < 1 THEN 1 " +
                "WHEN depth >= 1 AND depth < 2 THEN 2 WHEN depth >= 2 AND depth < 3 THEN 3 WHEN depth >= 3 THEN 4 END AS depthLevel " +
                "FROM b_r_cun WHERE s_id = ? AND kind = ?) as  s GROUP BY depthLevel,xz_name,t ORDER BY t,depthLevel";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, id, kind);
        JSONObject result = null;
        try {
            List<TimeData> fList = cDataTransformer(list);
            //time修正后的列表
            List<TimeData> updatedList = fList.stream()
                    .map(t -> new TimeData(t.t() * timeInterval, t.list()))
                    .toList();
            result = JSONUtil.parseObj(new ObjectMapper().writeValueAsString(Map.of("times", updatedList)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public JSONObject dmList(long id, String kind) {
        RehearsalScheme rehearsalScheme = this.getById(id);
        if (rehearsalScheme == null) {
            throw new SchemeNotFoundException("方案不存在");
        }
        int simulationDuration = rehearsalScheme.getSimulationDuration();
        int timeInterval = getTimeInterval(simulationDuration);
        String sql = "with t1 as(SELECT a.zh,IFNULL(b.depth,0) as depth, a.sjhsw,a.sjhdgc+IFNULL(b.depth,0) as z,a.lon,a.lat, b.t FROM b_e_dm a left join b_r_dm b on a.zh=b.zh and b.s_id=? and b.kind=?)," +
                "t2 as (select zh,lon,lat,MAX(depth) as max_depth,MAX(z) max_z  from t1 group by zh,lon,lat)," +
                "t3 as (select zh, min(t) as min_t from t1  where (z-sjhsw)>0 group by zh) " +
                "select t2.*,IFNULL(t3.min_t,0) as min_t from t2 left join t3 on t2.zh=t3.zh";
        JSONObject ret = new JSONObject();
        //分洪量
        ret.put("fhl",0);
        if(rehearsalScheme.getFhFlow()!=null)
            ret.put("fhl",rehearsalScheme.getFhFlow().multiply(BigDecimal.valueOf(rehearsalScheme.getSimulationDuration())));
        JSONArray times = new JSONArray();
        //修正时间
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, id, kind);
        for (Map<String, Object> map : list) {
            map.put("min_t", (Integer.parseInt(map.get("min_t").toString())) * timeInterval);
        }
        ret.set("list", list);
        for (int i = 0; i <= simulationDuration / timeInterval; i++) {
            sql = "SELECT a.zh,IFNULL(b.depth,0) as depth, a.sjhdgc+IFNULL(b.depth,0) as z FROM b_e_dm a left join b_r_dm b on a.zh=b.zh and b.t=? and b.s_id=? and b.kind=?";
            list = jdbcTemplate.queryForList(sql, i, id, kind);
            times.add(JSONUtil.createObj().set("t", i * timeInterval).set("list", JSONUtil.parseArray(list)));
            ret.set("times", times);
        }
        return ret;
    }

    @Override
    public JSONObject yldList(long id, String kind) {
        RehearsalScheme rehearsalScheme = this.getById(id);
        if (rehearsalScheme == null) {
            throw new SchemeNotFoundException("方案不存在");
        }
        int simulationDuration = rehearsalScheme.getSimulationDuration();
        int timeInterval = getTimeInterval(simulationDuration);
        String sql = "SELECT a.name,a.lon,a.lat,IFNULL(MAX(b.depth),0) as  max_depth," +
                "(select count(1) from b_r_yld c where c.name=a.name and c.depth>0.3 and c.s_id=? and kind=?) as js_hours FROM b_e_yld a" +
                " left join b_r_yld b on a.name=b.name and b.s_id=? and b.kind=? group by a.name,a.lon,a.lat";
        JSONObject ret = new JSONObject();
        JSONArray times = new JSONArray();
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, id, kind, id, kind);
        //修正时长
        for (Map<String, Object> map : list) {
            map.computeIfPresent("js_hours", (key, value) -> Integer.parseInt(String.valueOf(value)) * timeInterval);
        }
        ret.set("list", JSONUtil.parseArray(list));
        for (int i = 0; i <= simulationDuration / timeInterval; i++) {
            sql = "SELECT a.name,IFNULL(b.depth,0) as depth FROM b_e_yld a left join b_r_yld b on a.name=b.name and b.t=? and b.s_id=? and b.kind=?";
            list = jdbcTemplate.queryForList(sql, i, id, kind);
            times.add(JSONUtil.createObj().set("t", i * timeInterval).set("list", JSONUtil.parseArray(list)));
            ret.set("times", times);
        }
        return ret;
    }

    @Override
    public JSONArray imageList(RehearsalScheme rehearsalScheme, String kind) {
        JSONArray jsonArray = new JSONArray();
        if ("bfh".equals(kind) && rehearsalScheme.getStatus1() != 2) {
            throw new SchemeNotFoundException("方案未执行，请先执行方案在查询图片列表");
        } else if ("fh".equals(kind) && rehearsalScheme.getStatus2() != 2) {
            throw new SchemeNotFoundException("方案未执行，请先执行方案在查询图片列表");
        }
        //查询每个时间点的水深
        LambdaQueryWrapper<BRInfo> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq( BRInfo::getSId, rehearsalScheme.getId()).eq(BRInfo::getKind,kind)
                .orderByDesc(BRInfo::getT);
        List<BRInfo> infoList= this.brInfoService.list(queryWrapper);

        int simulationDuration = rehearsalScheme.getSimulationDuration();
        LocalDateTime createdTime = rehearsalScheme.getCreatedTime();
        ResponseData<JSONObject> responseData = rehearsalPythonService.calImageListApi(createdTime, rehearsalScheme.getId(), kind);
        JSONObject imageData = responseData.getData();
        int timeInterval = getTimeInterval(simulationDuration);
        String filePath = imageData.getStr("filePath");
        List<Integer> tList = imageData.get("tList", List.class);
        tList.forEach(t -> {
            JSONObject object = new JSONObject();
            object.set("t", t * timeInterval);
            double depth = 0;
            for(BRInfo info:infoList) {
                if(info.getT().equals(t)) {
                    depth = info.getDepth();
                    break;
                }

            }
            object.set("depth", depth);
            object.set("gray", Paths.get(filePath, String.valueOf(t), "gray.png").toString().replace("\\", "/"));
            object.set("color", Paths.get(filePath, String.valueOf(t), "color.png").toString().replace("\\", "/"));
            jsonArray.add(object);
        });

        return jsonArray;
    }

    /**
     * 根据配置文件获取模拟时长
     *
     * @param time 时长
     * @return 模拟时长
     */
    private int modelTime(int time) {
        int[] params = Arrays.stream(modelParam.split(","))
                .mapToInt(Integer::parseInt).sorted()
                .toArray();
        if (time > Arrays.stream(params).max().getAsInt()) {
            throw new ModelCalculationException("不支持的模型参数，当前仅支持" + modelParam);
        }
        for (int t : params) {
            if (time <= t) {
                return t;
            }
        }
        return time;
    }

    private void addZero(JSONArray array, int modelTime) {
        //时间间隔参数
        int timeInterval = getTimeInterval(modelTime);
        //时间间隔所需的模拟数量
        int num = modelTime / timeInterval;
        if (array.size() < num) {
            for (int i = array.size(); i < num; i++) {
                array.add(0);
            }
        }
    }

    @Override
    public ResponseEntity<byte[]> imagePreview(String filePath) {
        return rehearsalPythonService.callImageApi(filePath);
    }

    @Override
    @Transactional
    public Long runFast(FastRehearsalVO fastRehearsalVO) {
        BigDecimal fhFlow = fastRehearsalVO.getFhFlow();
        String kind = "bfh";
        if (fhFlow != null && fhFlow.compareTo(BigDecimal.ZERO) != 0) {
            kind = "fh";
        }
        FastRehearsalRainfallVO fastRehearsalRainfall = fastRehearsalVO.getRainfall();
        FastRehearsalFlowVO fastRehearsalFlow = fastRehearsalVO.getFlow();
        Integer rainfallTime = fastRehearsalRainfall.getTime();
        BigDecimal rainfall = fastRehearsalRainfall.getTotal();
        Integer flowTime = fastRehearsalFlow.getTime();
        int time = Math.max(rainfallTime, flowTime);
        int simulationDuration = modelTime(time);
        //调用python接口生成降雨列表
        ResponseData<List<BigDecimal>> response = rehearsalPythonService.calRainfallList(rainfallTime, rainfall);
        List<BigDecimal> rainfallList = response.getData();
        //生成降雨列表是每分钟的降雨量，需要按照降雨时长（h）进行汇总
        JSONArray rainfallProcess = calculateHourlySums(simulationDuration, rainfallList);

        //入参
        JSONObject paramsJson = new JSONObject();
        paramsJson.set("rainfall", fastRehearsalRainfall).set("flow", fastRehearsalFlow);
        JSONArray params = new JSONArray();
        addZero(rainfallProcess, simulationDuration);
        List<Double> qList = Collections.nCopies(flowTime, fastRehearsalFlow.getQ());
        JSONArray inq = JSONUtil.parseArray(qList);
        addZero(inq, simulationDuration);
        JSONArray fhq = new JSONArray();
        if ("fh".equals(kind)) {
            for (int i = 0; i < simulationDuration; i++) {
                fhq.add(fhFlow);
            }
        }
        addZero(fhq, simulationDuration);
        params.addAll(rainfallProcess);
        params.addAll(inq);
        params.addAll(fhq);
        //保存方案
        RehearsalScheme rehearsalScheme = new RehearsalScheme();
        rehearsalScheme.setType(RehearsalSchemeTypeEnum.FAST.getValue());
        rehearsalScheme.setName("快速预演");
        rehearsalScheme.setParamsJson(paramsJson.toString());
        rehearsalScheme.setSimulationDuration(simulationDuration);
        rehearsalScheme.setFhFlow(fhFlow);
        if ("fh".equals(kind)) {
            rehearsalScheme.setStatus1(0);
            rehearsalScheme.setStatus2(1);
            rehearsalScheme.setParamsFh(params.toString());
        } else {
            rehearsalScheme.setStatus1(1);
            rehearsalScheme.setStatus2(0);
            rehearsalScheme.setParamsBfh(params.toString());
        }
        this.save(rehearsalScheme);
        Long id = rehearsalScheme.getId();
        rehearsalPythonService.callPythonApi(rehearsalScheme, kind);
        return id;
    }

    public static List<TimeData> cDataTransformer(List<Map<String, Object>> inputList) {
        // 构建时间→层级→区域数据的映射结构
        Map<Integer, Map<Integer, List<AreaData>>> timeMap = new TreeMap<>();

        inputList.forEach(map -> {
            int level = Optional.ofNullable((Integer) map.get("depthLevel")).orElse(0);
            String name = (String) map.get("xz_name");
            int time = Optional.ofNullable((Integer) map.get("t")).orElse(0);
            BigDecimal area = (BigDecimal) map.get("totalArea");
            timeMap.computeIfAbsent(time, k -> new HashMap<>())
                    .computeIfAbsent(level, k -> new ArrayList<>())
                    .add(new AreaData(name, area));
        });

        // 转换为目标JSON结构
        return timeMap.entrySet().stream()
                .map(e -> new TimeData(
                        e.getKey(),
                        e.getValue().entrySet().stream()
                                .map(le -> new LevelData(le.getKey(), le.getValue()))
                                .collect(Collectors.toList())
                )).collect(Collectors.toList());
    }


    // 内部数据结构
    record AreaData(String name, BigDecimal area) {
    }

    record LevelData(int level, List<AreaData> list) {
    }

    record TimeData(int t, List<LevelData> list) {
    }


    @Override
    public void autoCreate() {
        ForecastScheme forecastScheme = forecastSchemeService.queryAutoForecastScheme();
        if (forecastScheme != null) {
            RehearsalScheme rehearsalScheme = new RehearsalScheme();
            rehearsalScheme.setType(RehearsalSchemeTypeEnum.AUTO.getValue());
            rehearsalScheme.setName("预演-" + forecastScheme.getName());
            String resultJsonStr = forecastScheme.getResultJson();
            if (StringUtils.isNoneEmpty(resultJsonStr)) {
                JSONArray bfhParams = new JSONArray();
                JSONObject resultJson = JSONUtil.parseObj(resultJsonStr);
                int simulationDuration = Arrays.stream(modelParam.split(","))
                        .mapToInt(Integer::parseInt).max().getAsInt();
                JSONObject paramsJson = new JSONObject();
                JSONArray rainfallProcess = resultJson.getJSONObject("rainResult").getJSONArray("rainProcess");
                paramsJson.set("rainfallProcess", getTimeIntervalProcess(simulationDuration, rainfallProcess));
                JSONArray flowProcess = resultJson.getJSONObject("riverSectionAnalysisDTO").getJSONArray("flowProcess");
                paramsJson.set("inq", getTimeIntervalProcess(simulationDuration, flowProcess));
                bfhParams.addAll(paramsJson.getJSONArray("rainfallProcess"));
                bfhParams.addAll(paramsJson.getJSONArray("inq"));
                JSONArray fhProcess = new JSONArray();
                bfhParams.addAll(getTimeIntervalProcess(simulationDuration, fhProcess));
                rehearsalScheme.setParamsJson(paramsJson.toString());
                rehearsalScheme.setStatus1(0);
                rehearsalScheme.setStatus2(0);
                rehearsalScheme.setSimulationDuration(simulationDuration);
                rehearsalScheme.setParamsBfh(bfhParams.toString());
                rehearsalScheme.setFhFlow(BigDecimal.ZERO);
                rehearsalScheme.setForecastId(forecastScheme.getId());
                if (this.save(rehearsalScheme)) {
                    this.runModelCall(rehearsalScheme, "bfh", true);
                }
            }
        }
    }

    /**
     * 根据模拟时长获取时间间隔所需的过程
     *
     * @param simulationDuration 模拟时长
     * @param process            原始过程（间隔1h）
     * @return 时间间隔所需的过程过程
     */
    private List<BigDecimal> getTimeIntervalProcess(int simulationDuration, JSONArray process) {
        List<BigDecimal> rainfallList = JSONUtil.toList(process, BigDecimal.class);
        List<BigDecimal> result = new ArrayList<>();
        //时间间隔参数
        int timeInterval = getTimeInterval(simulationDuration);
        //时间间隔所需的模拟数量
        int num = simulationDuration / timeInterval;

        for (int i = 0; i < num; i++) {
            int startIndex = i * timeInterval;
            int endIndex = (i + 1) * timeInterval;
            BigDecimal value = BigDecimal.ZERO;
            if (endIndex > rainfallList.size()) {
                endIndex = rainfallList.size();
            }
            if (startIndex < rainfallList.size()) {
                List<BigDecimal> sublist = rainfallList.subList(startIndex, endIndex);
                value = sublist.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            result.add(value.setScale(2, RoundingMode.HALF_UP));
        }

        if (result.size() < num) {
            //不够需要补0
            for (int i = result.size(); i < num; i++) {
                result.add(BigDecimal.ZERO);
            }
        }
        return result;
    }

    @Override
    public Page<RehearsalScheme> getFinishedList(int page, int size, String name) {
        LambdaQueryWrapper<RehearsalScheme> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RehearsalScheme::getStatus1, 2)
                .and(wq -> wq.eq(RehearsalScheme::getType, 0).or().eq(RehearsalScheme::getType, 1));
        if (ObjectUtils.isNotEmpty(name)) {
            queryWrapper.like(RehearsalScheme::getName, name);
        }
        queryWrapper.orderByDesc(RehearsalScheme::getCreatedTime);
        return this.page(new Page<>(page, size), queryWrapper);
    }

    /**
     * 根据模拟时长获取时间间隔参数
     *
     * @param simulationDuration 模拟时长
     * @return 时间间隔参数（单位：小时）
     */
    private int getTimeInterval(int simulationDuration) {
        return simulationDuration == 24 ? 2 : 1;
    }

    /**
     * 汇总统计降雨量，生成按照时间间隔汇总的降雨列表
     *
     * @param modelDuration 模型时长（N小时）
     * @param list          每分钟的降雨列表
     * @return 按照时间间隔汇总的降雨列表
     */
    private JSONArray calculateHourlySums(Integer modelDuration, List<BigDecimal> list) {
        //时间间隔参数
        int timeInterval = getTimeInterval(modelDuration);
        //时间间隔所需的列表数量
        int num = modelDuration / timeInterval;
        List<BigDecimal> doubles = IntStream.range(0, num)
                .mapToObj(hour -> {
                    int startIndex = hour * 60 * timeInterval;
                    int endIndex = (hour + 1) * 60 * timeInterval;
                    BigDecimal sum = BigDecimal.ZERO;
                    if (endIndex > list.size()) {
                        endIndex = list.size();
                    }
                    if (startIndex < list.size()) {
                        sum = list.subList(startIndex, endIndex)
                                .stream()
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                    return sum.setScale(2, RoundingMode.HALF_UP);
                })
                .toList();
        return JSONUtil.parseArray(doubles);
    }

}



